<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>🌟 关卡 4｜watch & watchEffect：侧效应"侦察兵"</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <style>
    body {
      font-family: 'Arial', sans-serif;
      max-width: 900px;
      margin: 0 auto;
      padding: 20px;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
    }
    .container {
      background: white;
      border-radius: 15px;
      padding: 30px;
      margin: 20px 0;
      box-shadow: 0 10px 30px rgba(0,0,0,0.2);
    }
    .title {
      color: #42b983;
      text-align: center;
      font-size: 28px;
      margin-bottom: 30px;
      text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
    }
    .section {
      background: #f8f9fa;
      border-radius: 10px;
      padding: 20px;
      margin: 20px 0;
      border-left: 5px solid #42b983;
    }
    .section h3 {
      color: #333;
      margin-top: 0;
    }
    .code-block {
      background: #2d3748;
      color: #e2e8f0;
      padding: 15px;
      border-radius: 8px;
      font-family: 'Courier New', monospace;
      margin: 10px 0;
      overflow-x: auto;
    }
    .control-panel {
      background: #e8f5e8;
      border-radius: 10px;
      padding: 20px;
      margin: 20px 0;
      border: 2px solid #42b983;
    }
    .control-group {
      margin: 15px 0;
      display: flex;
      align-items: center;
      gap: 15px;
    }
    .slider-container {
      flex: 1;
    }
    .slider {
      width: 100%;
      height: 8px;
      border-radius: 4px;
      background: #ddd;
      outline: none;
      margin: 10px 0;
    }
    .slider::-webkit-slider-thumb {
      appearance: none;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: #42b983;
      cursor: pointer;
    }
    button {
      background: #42b983;
      color: white;
      border: none;
      padding: 10px 20px;
      border-radius: 6px;
      cursor: pointer;
      font-size: 14px;
      transition: background 0.3s;
    }
    button:hover {
      background: #3aa876;
    }
    button:disabled {
      background: #ccc;
      cursor: not-allowed;
    }
    .monitor {
      background: #1a202c;
      color: #68d391;
      padding: 15px;
      border-radius: 8px;
      font-family: 'Courier New', monospace;
      height: 200px;
      overflow-y: auto;
      margin: 10px 0;
      border: 2px solid #2d3748;
    }
    .monitor-line {
      margin: 5px 0;
      padding: 2px 0;
    }
    .drone-icon {
      display: inline-block;
      animation: fly 2s infinite;
    }
    @keyframes fly {
      0%, 100% { transform: translateY(0px); }
      50% { transform: translateY(-3px); }
    }
    .camera-icon {
      display: inline-block;
      animation: blink 1s infinite;
    }
    @keyframes blink {
      0%, 50% { opacity: 1; }
      51%, 100% { opacity: 0.3; }
    }
    .highlight {
      color: #e74c3c;
      font-weight: bold;
    }
    .analogy {
      background: linear-gradient(45deg, #ff6b6b, #feca57);
      color: white;
      padding: 15px;
      border-radius: 10px;
      margin: 15px 0;
      text-align: center;
      font-weight: bold;
    }
    .data-display {
      background: #f0f8ff;
      border: 2px solid #42b983;
      border-radius: 8px;
      padding: 15px;
      margin: 10px 0;
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="container">
      <h1 class="title">🌟 关卡 4｜watch & watchEffect：侧效应"侦察兵"</h1>
      
      <div class="analogy">
        <p>📹 watch 是"定点监控摄像头"；🛸 watchEffect 是"AI 巡检无人机"</p>
        <p>一个精确监控，一个智能巡航，各司其职！</p>
      </div>

      <!-- Watch 示例区域 -->
      <div class="section">
        <h3>📹 定点监控摄像头 - watch</h3>
        <p>精确监听指定数据源，可拿到新旧值进行对比</p>
        
        <div class="control-panel">
          <div class="control-group">
            <label>任务ID：</label>
            <input type="number" v-model.number="taskId" min="1" max="10" style="width: 80px; padding: 5px;">
            <button @click="fetchTaskData" :disabled="isLoading">
              {{ isLoading ? '加载中...' : '获取任务数据' }}
            </button>
          </div>
          
          <div class="data-display" v-if="taskData">
            <h4>任务详情：</h4>
            <p><strong>标题：</strong> {{ taskData.title }}</p>
            <p><strong>状态：</strong> 
              <span :class="{ highlight: taskData.completed }">
                {{ taskData.completed ? '✅ 已完成' : '⏳ 进行中' }}
              </span>
            </p>
            <p><strong>用户ID：</strong> {{ taskData.userId }}</p>
          </div>
        </div>
        
        <div class="monitor">
          <div v-for="log in watchLogs" :key="log.id" class="monitor-line">
            <span class="camera-icon">📹</span> {{ log.message }}
          </div>
        </div>
      </div>

      <!-- WatchEffect 示例区域 -->
      <div class="section">
        <h3>🛸 AI 巡检无人机 - watchEffect</h3>
        <p>立即运行一次，并收集依赖，适合"自动触发"场景</p>
        
        <div class="control-panel">
          <div class="control-group">
            <label>角色坐标：</label>
            <div class="slider-container">
              <div>X 坐标: <span class="highlight">{{ characterX }}</span></div>
              <input type="range" v-model.number="characterX" min="0" max="100" class="slider">
            </div>
          </div>
          
          <div class="control-group">
            <div class="slider-container">
              <div>Y 坐标: <span class="highlight">{{ characterY }}</span></div>
              <input type="range" v-model.number="characterY" min="0" max="100" class="slider">
            </div>
          </div>
          
          <div class="control-group">
            <button @click="moveToCenter">移动到中心</button>
            <button @click="randomMove">随机移动</button>
            <button @click="clearEffectLogs">清空日志</button>
          </div>
        </div>
        
        <div class="monitor">
          <div v-for="log in effectLogs" :key="log.id" class="monitor-line">
            <span class="drone-icon">🛸</span> {{ log.message }}
          </div>
        </div>
      </div>

      <!-- 代码示例区域 -->
      <div class="section">
        <h3>💻 代码示例</h3>
        
        <div>
          <h4>📹 watch 示例代码：</h4>
          <div class="code-block">
const taskId = ref(1)
const taskData = ref(null)

// 监听 taskId 变化，拉取新数据
watch(taskId, async (newId, oldId) => {
  console.log(`任务ID 从 ${oldId} → ${newId}`)
  const res = await fetch(`https://jsonplaceholder.typicode.com/todos/${newId}`)
  taskData.value = await res.json()
}, { immediate: true })
          </div>
        </div>
        
        <div>
          <h4>🛸 watchEffect 示例代码：</h4>
          <div class="code-block">
const characterX = ref(0)
const characterY = ref(0)

// 只要 X 或 Y 变，就打印最新坐标
watchEffect(() => {
  console.log(`角色坐标：(${characterX.value}, ${characterY.value})`)
})
          </div>
        </div>
      </div>

      <!-- 学习要点 -->
      <div class="section">
        <h3>📚 学习要点</h3>
        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
          <div style="background: #e8f5e8; padding: 15px; border-radius: 8px;">
            <h4>📹 watch 特点：</h4>
            <ul>
              <li>精确监听指定数据源</li>
              <li>可获取新旧值对比</li>
              <li>支持异步操作</li>
              <li>可配置 immediate、deep 等选项</li>
            </ul>
          </div>
          <div style="background: #e8f0ff; padding: 15px; border-radius: 8px;">
            <h4>🛸 watchEffect 特点：</h4>
            <ul>
              <li>自动收集依赖</li>
              <li>立即执行一次</li>
              <li>代码更简洁</li>
              <li>适合自动触发场景</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    const { createApp, ref, watch, watchEffect } = Vue;

    createApp({
      setup() {
        // Watch 相关数据
        const taskId = ref(1);
        const taskData = ref(null);
        const isLoading = ref(false);
        const watchLogs = ref([]);
        let watchLogId = 0;

        // WatchEffect 相关数据
        const characterX = ref(50);
        const characterY = ref(50);
        const effectLogs = ref([]);
        let effectLogId = 0;

        // 添加 watch 日志
        const addWatchLog = (message) => {
          watchLogs.value.push({
            id: watchLogId++,
            message: `[${new Date().toLocaleTimeString()}] ${message}`
          });
        };

        // 添加 effect 日志
        const addEffectLog = (message) => {
          effectLogs.value.push({
            id: effectLogId++,
            message: `[${new Date().toLocaleTimeString()}] ${message}`
          });
        };

        // 获取任务数据
        const fetchTaskData = async () => {
          isLoading.value = true;
          try {
            const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${taskId.value}`);
            taskData.value = await response.json();
            addWatchLog(`✅ 成功获取任务数据：${taskData.value.title}`);
          } catch (error) {
            addWatchLog(`❌ 获取数据失败：${error.message}`);
          } finally {
            isLoading.value = false;
          }
        };

        // 移动到中心
        const moveToCenter = () => {
          characterX.value = 50;
          characterY.value = 50;
        };

        // 随机移动
        const randomMove = () => {
          characterX.value = Math.floor(Math.random() * 101);
          characterY.value = Math.floor(Math.random() * 101);
        };

        // 清空 effect 日志
        const clearEffectLogs = () => {
          effectLogs.value = [];
        };

        // 设置 watch - 监听 taskId 变化
        watch(taskId, async (newId, oldId) => {
          addWatchLog(`🎯 检测到任务ID变化：${oldId} → ${newId}`);
          await fetchTaskData();
        }, { immediate: true });

        // 设置 watchEffect - 监听坐标变化
        watchEffect(() => {
          const x = characterX.value;
          const y = characterY.value;
          addEffectLog(`🛸 角色坐标更新：(${x}, ${y})`);
          
          // 添加一些智能判断
          if (x === 50 && y === 50) {
            addEffectLog('🎯 角色位于地图中心！');
          } else if (x > 80 && y > 80) {
            addEffectLog('⚠️ 角色接近地图边缘！');
          }
        });

        // 初始日志
        addWatchLog('📹 定点监控摄像头已启动');
        addEffectLog('🛸 AI 巡检无人机已起飞');

        return {
          // 数据
          taskId,
          taskData,
          isLoading,
          watchLogs,
          characterX,
          characterY,
          effectLogs,
          // 方法
          fetchTaskData,
          moveToCenter,
          randomMove,
          clearEffectLogs
        };
      }
    }).mount('#app');
  </script>
</body>
</html>